package tcpserver

import (
	"bufio"
	//"bytes"
	"encoding/binary"
	"errors"
	//"fmt"
	//"io"
	"net/textproto"
	"strings"
	"sync"
	"unicode/utf16"
)

//////////////////////////////////////////////////////////////
// 协议的定义

// 开始码
const START_CODE = 0x45F9AC5C

// 同步码：  ( 4 BYTES )
const SYNC_CODE = 0xAC8F79B3

// 结束码：  ( 4 BYTES )
const END_CODE = 0x68AB289F

// 数据头部信息
type DataHeader struct {
	StartCode  uint32
	Cmd        uint16
	Series     uint16 // iptv 文件类型记录处
	DataLength uint32
	SynCode    uint32
}

// 数据尾部信息
type DataFooter struct {
	EndCode uint32
}

func (d *DataHeader) Reset() {
	d.StartCode = START_CODE
	d.SynCode = SYNC_CODE
	d.Cmd = 0
	d.DataLength = 0
	d.Series = 0
}

func (d *DataFooter) Reset() {
	d.EndCode = END_CODE
}

// 请求的信息
type Request struct {

	// 命令码
	Cmd uint16

	// 协议头部
	Header DataHeader

	//  协议内容
	DataBody []byte

	// 协议尾部
	Footer DataFooter

	// Close indicates whether to close the connection after
	// replying to this request (for servers) or after sending
	// the request (for clients).
	Close bool

	// RemoteAddr allows HTTP servers and other software to record
	// the network address that sent the request, usually for
	// logging. This field is not filled in by ReadRequest and
	// has no defined format. The HTTP server in this package
	// sets RemoteAddr to an "IP:port" address before invoking a
	// handler.
	// This field is ignored by the HTTP client.
	RemoteAddr string

	// local address
	LocalAddr string

	// Cancel is an optional channel whose closure indicates that the client
	// request should be regarded as canceled. Not all implementations of
	// RoundTripper may support Cancel.
	//
	// For server requests, this field is not applicable.
	Cancel <-chan struct{}

	conn *conn
}

// 获取用户数据
func (r *Request) GetUserData(key string) string {
	val, ok := r.conn.userdata[key]
	if ok {
		return val
	} else {
		return string("")
	}
}

// 设置用户数据
func (r *Request) SetUserData(key string, data string) {
	r.conn.userdata[key] = data
}

// 设置令牌
func (r *Request) SetToken(token uint64) {
	r.conn.token = token
}

// 获取远端的IP地址
func (r *Request) RemoteIP() string {
	pos := strings.Index(r.RemoteAddr, ":")
	if pos > 0 {
		return r.RemoteAddr[0:pos]
	} else {
		return r.RemoteAddr
	}
}

// 获取本地的IP地址
func (r *Request) LocalIP() string {
	pos := strings.Index(r.LocalAddr, ":")
	if pos > 0 {
		return r.LocalAddr[0:pos]
	} else {
		return r.LocalAddr
	}
}

//解析接收到的数据
func ReadRequest(b *bufio.Reader) (*Request, error) {

	req := new(Request)

	err1 := binary.Read(b, binary.LittleEndian, &(req.Header))
	if err1 != nil {
		return nil, err1
	}

	req.Cmd = req.Header.Cmd

	if req.Header.StartCode != START_CODE {
		return nil, errors.New("KTV: START-CODE is WRONG!")
	}

	if req.Header.SynCode != SYNC_CODE {
		return nil, errors.New("KTV: SYNC_CODE is WRONG!")
	}

	// new reader to read body
	req.DataBody = make([]byte, req.Header.DataLength)
	b.Read(req.DataBody)

	err2 := binary.Read(b, binary.LittleEndian, &req.Footer)
	if err2 != nil {
		return nil, err2
	}

	if req.Footer.EndCode != END_CODE {
		return nil, errors.New("KTV: END_CODE is WRONG!")
	}

	return req, nil
}

var textprotoReaderPool sync.Pool

func newTextprotoReader(br *bufio.Reader) *textproto.Reader {
	if v := textprotoReaderPool.Get(); v != nil {
		tr := v.(*textproto.Reader)
		tr.R = br
		return tr
	}
	return textproto.NewReader(br)
}

func putTextprotoReader(r *textproto.Reader) {
	r.R = nil
	textprotoReaderPool.Put(r)
}

// KTV 请求信息
type KtvRequestInfo struct {
	FileName [40]uint16 // // 文件名， 80 BYTES
	Number   uint32     //    歌曲编号

	Start       uint32 //  请求文件的开始位置
	Length      uint32 //  请求数据长度, 0时发送剩余文件数据
	FastForward uint32 // 快进多少
	FFLength    uint32 // 快进读取长度

	Ext [4]uint16 // 8 BYTES 请求的文件后缀名

}

const KtvRequestStructSize = 108

//  二进制数据转换为请求信息结构体
func GetKtvRequestInfo(buf []byte) *KtvRequestInfo {
	info := new(KtvRequestInfo)

	if len(buf) < KtvRequestStructSize {
		return info
	}

	for i := 0; i < 40; i++ {
		offset1 := i * 2
		offset2 := i*2 + 2
		info.FileName[i] = binary.LittleEndian.Uint16(buf[offset1:offset2])
	}

	info.Number = binary.LittleEndian.Uint32(buf[80:84])

	info.Start = binary.LittleEndian.Uint32(buf[84:88])
	info.Length = binary.LittleEndian.Uint32(buf[88:92])
	info.FastForward = binary.LittleEndian.Uint32(buf[92:96])
	info.FFLength = binary.LittleEndian.Uint32(buf[96:100])

	for i := 0; i < 4; i++ {
		offset1 := 100 + i*2
		offset2 := 100 + i*2 + 2
		info.Ext[i] = binary.LittleEndian.Uint16(buf[offset1:offset2])
	}

	return info
}

// 获取文件名称
// 转换得出utf-8编码的string
func (r *KtvRequestInfo) GetFileName() string {
	return UTF16ToString(r.FileName[:])
}

// 重新计算发送文件的参数
// 函数返回新的偏移位置和长度

// UTF16ToString returns the UTF-8 encoding of the UTF-16 sequence s,
// with a terminating NUL removed.
func UTF16ToString(s []uint16) string {
	for i, v := range s {
		if v == 0 {
			s = s[0:i]
			break
		}
	}
	return string(utf16.Decode(s))
}
